/**
 * LinkedLST
 * May 11, 2011
 * ItemView.java - Displays information about an item
 */

package edu.washington.cs.labspecimentransport;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.conn.ConnectTimeoutException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TabHost.TabContentFactory;
import android.widget.TabHost.TabSpec;
import edu.washington.cs.labspecimentransport.adapters.BarcodeAdapter;
import edu.washington.cs.labspecimentransport.adapters.CommentsViewAdapter;
import edu.washington.cs.labspecimentransport.adapters.PredicateLayout;
import edu.washington.cs.labspecimentransport.adapters.SeparatedListAdapter;
import edu.washington.cs.labspecimentransport.data.DataQuery;
import edu.washington.cs.labspecimentransport.dataobjects.Comment;
import edu.washington.cs.labspecimentransport.dataobjects.Item;
import edu.washington.cs.labspecimentransport.dataobjects.ItemAttribute;
import edu.washington.cs.labspecimentransport.dataobjects.ItemType;
import edu.washington.cs.labspecimentransport.dataobjects.Location;
import edu.washington.cs.labspecimentransport.ops.CommonHandlers;
import edu.washington.cs.labspecimentransport.ops.Conversion;
import edu.washington.cs.labspecimentransport.ops.Keys;

/**
 * An ItemView that displays information about a bag or specimen.
 * 
 * <p>
 * An intent with the following keys are expected:
 * 	int : KEY_ITEMID - the item id
 * 	int : KEY_COURIERID - the courier id
 *  ArrayList<String> : KEY_BARCODE - the item's barcodes
 *  boolean : KEY_ISCONTAINER - whether the item is a container
 */

public class ItemView extends Activity {

	private DataQuery dq;
	private Bundle infoBundle;
	private TabHost tabHost;

	private Item item;						// the item to display information about
	private int item_id;					// the id of the item
	private ArrayList<String> item_barcode;	// the barcodes associated with the item
	private boolean item_iscontainer;		// true if the item is a container
	private Location fromLoc;				// the Location where item was sent from
	private Location destLoc;				// the Location where item is being sent to	

	private List<ItemAttribute> listOfAttributes;	// list of item's attributes
	private List<Comment> listOfComments;			// list of item's comments
	private List<String> listOfAuthors;				// list of item's comment authors
	
	// If the item is a container, following variables are also used:
	private Map<ItemAttribute, Integer> mapOfColors;// list of container's color counts
	private List<Item> listOfBagContents;			// list of container's contents

	// map of ids->barcodes for specimens and containers
	private HashMap<Integer, ArrayList<String>> specimenIdAndBarcodes;         
	private HashMap<Integer, ArrayList<String>> containerIdAndBarcodes;

	// flag for whether or not initialization of activity has occured
	private boolean firstExecution;		
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.item);
		firstExecution = true;

		dq = DataQuery.getInstance();

		setupButtons();
		updateInfo();
	}

    /**
     * Define the options menu.
     */
	public boolean onCreateOptionsMenu(Menu menu) {
    	menu.add(0, Keys.MENUID_REFRESH, 0, R.string.option_refresh);
    	menu.add(0, Keys.MENUID_HOME, 0, R.string.option_home);
    	menu.add(0, Keys.MENUID_HELP, 0, R.string.option_help);
    	return true;
    }

    /**
     * Define functionality for each item in options menu.
     */
    public boolean onOptionsItemSelected(MenuItem item) {   
        switch(item.getItemId()) {
        case Keys.MENUID_REFRESH:
        	dq.flushEntireCache();
        	updateInfo();
        	break;
        	
        case Keys.MENUID_HOME:
        	CommonHandlers.returnHome(this);
        	break;
        
        case Keys.MENUID_HELP:
        	CommonHandlers.startHelp(this);
        	break;
        	
        default:
        	super.onOptionsItemSelected(item);
        	break;
    }
        
        return true;
    }
	
    /**
     * On resume, change screen orientation to portrait in case we
     * are returning from BarcodeView.
     */
	protected void onResume() {
		super.onResume();
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
	}

	/**
	 * Re-query the database and update information.
	 */
	private void updateInfo() {
		new Update().execute();
	}	

	/**
	 * Sets onClick handlers for all buttons
	 */
	private void setupButtons() {
		// onClick handler for "Home" button
		Button h = (Button) findViewById(R.id.home_button);
		h.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				Intent i = new Intent(ItemView.this, HomeView.class);
				i.putExtras(infoBundle);
				startActivity(i);
			}
		}); 

		// onClick handler for "Refresh" button
		Button r = (Button) findViewById(R.id.refresh_button);
		r.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				dq.flushEntireCache();
				updateInfo();
			}
		}); 
	}

	/**
	 * Retrieve item information
	 */
	private void getInfo() throws ConnectTimeoutException {
		// item info
		item = dq.getItemById(item_id);

		// ids of source and destination locations
		int clientId = item.getSource_id();
		int destId = item.getDestination_id();

		// source and destination locations
		fromLoc = dq.getLocationFromId(clientId);
		destLoc = dq.getLocationFromId(destId);

		// attributes
		listOfAttributes = dq.getAttributesByItemId(item_id);

		// colors
		if (item_iscontainer) {
			mapOfColors = dq.getCountOfColorsForBag(item_barcode.get(0));
		}
	}

	/**
	 * Retrieve the list of comments
	 */
	private void getComments() throws ConnectTimeoutException {
		listOfComments = dq.getCommentsByItemId(item_id);
		listOfAuthors = new ArrayList<String>();
		for (Comment c : listOfComments) {
			String author = dq.getUserNameById(c.getUser_id());
			listOfAuthors.add(author);
		}
	}

	/**
	 * Retrieve the items and contents inside a bag
	 */
	private void getBagContents() throws ConnectTimeoutException {
		listOfBagContents = dq.getItemsByBag(item_id);

		List<Integer> idsOfBagContents = Conversion.convertItemsToItemIds(listOfBagContents);
		List<ItemType> itemTypes = dq.getItemTypesByIds(idsOfBagContents);

		List<Integer> specimens = new ArrayList<Integer>();
		List<Integer> containers = new ArrayList<Integer>();

		for (int i = 0; i < itemTypes.size(); i++) {
			ItemType curr = itemTypes.get(i);
			if (curr.getIs_container()) {
				containers.add(idsOfBagContents.get(i));
			} else {
				specimens.add(idsOfBagContents.get(i));
			}
		}

		// convert list of items to a map of ids to barcodes
		specimenIdAndBarcodes = Conversion.convertItemIdListToBarcodeList(specimens);         
		containerIdAndBarcodes = Conversion.convertItemIdListToBarcodeList(containers);
	}

	/**
	 * Display the content of each of the tabs
	 */
	private void displayInfo() {
		// =================================
		// From
		// =================================
		TextView from = (TextView) findViewById(R.id.from);
		from.setText(fromLoc.getName());

		// =================================
		// Destination
		// =================================
		TextView destination = (TextView) findViewById(R.id.destination);
		destination.setText(destLoc.getName());

		// =================================
		// Attributes
		// =================================
		PredicateLayout attributes = (PredicateLayout) findViewById(R.id.attributes);
		attributes.removeAllViews();
		for (ItemAttribute a : listOfAttributes) {
			TextView t = new TextView(this);
			t.setText(a.getDisplay_text());
			t.setBackgroundColor(Color.GRAY);
			t.setSingleLine(true);
			t.setPadding(8, 5, 8, 5);
			attributes.addView(t, new PredicateLayout.LayoutParams(3, 3));
		}

		// =================================
			// Colors
			// =================================
		if (item_iscontainer) {
			PredicateLayout colors = (PredicateLayout) findViewById(R.id.colors);
			colors.removeAllViews();
			for (Map.Entry<ItemAttribute, Integer> c : mapOfColors.entrySet()) {
				TextView t = new TextView(this);
				t.setText(c.getKey().getDisplay_text() + ": " + c.getValue());
				t.setBackgroundColor(Color.GRAY);
				t.setSingleLine(true);
				t.setPadding(8, 5, 8, 5);
				colors.addView(t, new PredicateLayout.LayoutParams(3, 3));
			}
		} else {
			TextView colors_label = (TextView) findViewById(R.id.colors_label);
			colors_label.setVisibility(TextView.GONE);
		}
	}	

	/** 
	 * Sets up the views, including the tabs 
	 */
	private void setViews() {
		// =================================
		// code below sets up the header
		// =================================

		TextView header = (TextView) findViewById(R.id.headerTitle);
		if (item_barcode.size() < 18) {
			header.setText(item_barcode.get(0));
		} else {
			header.setText(item_barcode.get(0).substring(0, 18) + "...");
		}

		// =================================
		// code below sets up the tabs
		// =================================

		tabHost = (TabHost) findViewById(R.id.tb);
		tabHost.setup();

		// info
		ScrollView firstTab = (ScrollView) findViewById(R.id.first_tab);

		// list of comments
		ListAdapter comments_adapter = new CommentsViewAdapter(this, listOfComments, listOfAuthors);
		ListView secondTab = (ListView) findViewById(R.id.second_tab);
		secondTab.setAdapter(comments_adapter);

		// bag contents
		SeparatedListAdapter bag_adapter = new SeparatedListAdapter(this);
		bag_adapter.addSection(
				getString(R.string.client_ui_specimenHeader) + 
        		" (" + specimenIdAndBarcodes.size() + " " + getString(R.string.client_ui_items) + ")", 
				new BarcodeAdapter(this, specimenIdAndBarcodes));
		bag_adapter.addSection(getString(R.string.client_ui_containerHeader) + 
        		" (" + containerIdAndBarcodes.size() + " " + getString(R.string.client_ui_items) + ")", 
				new BarcodeAdapter(this, containerIdAndBarcodes));
		ListView thirdTab = (ListView) findViewById(R.id.third_tab);
		thirdTab.setAdapter(bag_adapter);
		thirdTab.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				TextView clickedView = (TextView) view.findViewById(R.id.item_id);
				Integer clickedItem = (Integer) clickedView.getTag();

				new initItemLookup(clickedItem).execute();
			}	
		});

		// setup the tabs
		if (firstExecution) {
			tabHost.getTabWidget().setDividerDrawable(R.drawable.item_tab_divider);
			setupTab(firstTab, getString(R.string.item_ui_tabs_info));
			setupTab(secondTab, getString(R.string.item_ui_tabs_comments));
			if (item_iscontainer) {
				setupTab(thirdTab, getString(R.string.item_ui_tabs_inBag));
			}
			tabHost.setCurrentTab(0);
		}
	}	

	/** 
	 * A helper method for setting up tabs 
	 */
	private void setupTab(final View view, final String tag) {
		View tabview = createTabView(tabHost.getContext(), tag);
		TabSpec setContent = tabHost.newTabSpec(tag).setIndicator(tabview).setContent(new TabContentFactory() {
			public View createTabContent(String tag) {
				return view;
			}
		});
		tabHost.addTab(setContent);
	}

	/** 
	 * Create the views of the tabs 
	 */
	private static View createTabView(final Context context, final String text) {
		View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null);
		TextView tv = (TextView) view.findViewById(R.id.tabsText);
		tv.setText(text);
		return view;
	}    

	/** 
	 * Extract information from intent 
	 */
	private void getPassedData() {
		infoBundle = getIntent().getExtras();
		item_id = infoBundle.getInt(Keys.KEY_ITEMID);
		item_barcode = infoBundle.getStringArrayList(Keys.KEY_BARCODE);
		item_iscontainer = infoBundle.getBoolean(Keys.KEY_ISCONTAINER);
	}   

	/**
	 * Service to get items from the backend database
	 */
	private class Update extends AsyncTask<Void, Void, Void> {
		private ProgressDialog dialog;
		private boolean success;
		private boolean timeout;
		
		// before execution
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			success = true;
			timeout = false;
			dialog = ProgressDialog.show(ItemView.this, "", "Loading...", true, true,
					new DialogInterface.OnCancelListener(){
				public void onCancel(DialogInterface dialog) {
					Update.this.cancel(true);
					finish();
				}
			});
		}

		// execution
		@Override
		protected Void doInBackground(Void... v) {
			try {
				if (firstExecution) {
					getPassedData();	// get required information from intent
				}

				getInfo();				// get item information
				getComments();			// get comments for this item
				getBagContents();		// get the bag's contents
			} catch (NullPointerException e) {
				success = false;
			} catch (ConnectTimeoutException e) {
				timeout = true;
			}
			return null;
		}

		// after execution
		@Override
		protected void onPostExecute(Void unused) {
			dialog.dismiss();
			if (success) {
				displayInfo();
				setViews();
				if (firstExecution) {
					firstExecution = false;
				}
			} else if (timeout) {
				Toast toast = Toast.makeText(ItemView.this, 
						R.string.error_default, Toast.LENGTH_LONG);
				toast.show();
			} else {
				Toast toast = Toast.makeText(ItemView.this, 
						R.string.error_default, Toast.LENGTH_LONG);
				toast.show();
			}
		}
	} 

	/**
	 * Service to lookup an item inside a container.
	 */
	private class initItemLookup extends AsyncTask<Void, Void, Void> {
		ProgressDialog dialog;
		private int item_id;
		private Intent intent;

		public initItemLookup(int item_id) {
			this.item_id = item_id;
		}

		// before execution
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			dialog = new ProgressDialog(ItemView.this);
			dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			dialog.setMessage("");
			dialog.setCancelable(true);
			dialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
				public void onCancel(DialogInterface dialog) {
					initItemLookup.this.cancel(true);
					finish();
				}
			});

			dialog = ProgressDialog.show(ItemView.this, "", "Loading...", true);
		}

		// execution
		@Override
		protected Void doInBackground(Void... params) {
			intent = new Intent(ItemView.this, ItemView.class);
			Bundle newBundle = new Bundle();
			newBundle.putAll(infoBundle);
			newBundle.putInt(Keys.KEY_ITEMID, item_id);

			if (containerIdAndBarcodes.containsKey(item_id)) {
				newBundle.putStringArrayList(Keys.KEY_BARCODE, containerIdAndBarcodes.get(item_id));
				newBundle.putBoolean(Keys.KEY_ISCONTAINER, true);
			} else {
				newBundle.putStringArrayList(Keys.KEY_BARCODE, specimenIdAndBarcodes.get(item_id));
				newBundle.putBoolean(Keys.KEY_ISCONTAINER, false);
			}

			intent.putExtras(newBundle);
			return null;
		}

		// after execution
		@Override
		protected void onPostExecute(Void unused) {
			startActivity(intent);
			dialog.dismiss();
		}
	}	
}
